#include "../include/ThreadPool.h"
#include "../include/WebPageQuery.h"
#include "../include/TcpServer.h"
#include <iostream>
#include <unistd.h>
#include <stdlib.h>
#include "../include/KeyRecommander.h"
#include "../include/CacheManager.h"
#include "../include/Timerfd.h"
#include "../include/MyLogger.h"
using std::cout;
using std::endl;

string func(const char *msg)
{
      string s1 = string(__FILE__) + string(":")
          + string(__FUNCTION__) + string(":")
          + string(std::to_string(__LINE__))
          + string(":") + msg;
           return s1;
}
class Train
{
public:
    int length;
    int id;
    string msg;
};
class MyTask
{
public:
    MyTask(const Train& msg, const TcpConnectionPtr & conn)
    : _msg(msg)
    , _conn(conn)
    {}
    
    //计算线程
    void process()
    {
        //cout << "process(): " << pthread_self() << endl;
        cout << "线程-缓存编号:" << current_thread::name << endl;
        //cout << "receive from client:" << _msg.msg << endl;
        //获取缓存管理器对象
        CacheManager* chmanager = CacheManager::getInstance();
        int cacheNumber = atoi(current_thread::name);
        
        json jsc;
        json tmp = json::parse(_msg.msg);
        
        //用日志记录下关键字的信息
        string temp="success receive:"+_msg.msg;
        logInfo(temp);
        
        _msg.msg = tmp.get<string>();   //将_msg转成c++对象
        string key = _msg.msg;
        //根据消息id,调用不同的服务接口
        if(_msg.id == 1)
        {
#if 0
            //关键字推荐
            KeyRecommander kr(_msg.msg,_conn);

            _msg.msg = kr.doQuery();
            _msg.id = 100;
            _msg.length = _msg.msg.size();
#endif
            jsc = chmanager->getCache(cacheNumber).doQuery(_msg.msg);
            vector<string> vc = jsc.get<vector<string>>();  
            if(vc.size() == 0)
            {
                cout << "缓存没有数据，走数据库查询" << endl;
                logInfo("缓存没有数据，走数据库查询");

                KeyRecommander kr(_msg.msg,_conn);
                _msg.msg = kr.doQuery();
                //反序列化
                json jsm = json::parse(_msg.msg);
                //js对象还原成c++对象
                vector<string> vm = jsm.get<vector<string>>();
                //判断数据库是否命中
                if(vm.size() == 0)
                {
                    //日志记录下报错信息
                    logError("-------404 found!---------");
                    logError("数据库也没有命中");

                    //数据库也没有命中
                    json jsres = "-------404 found!---------";
                    _msg.msg = jsres.dump();
                }
                else
                {
                    //数据库命中，加入缓存
                    cout << "数据库命中,加入缓存" << endl;
                    //发送的是json，而不是json字符串
                    logInfo("数据库命中,加入缓存");
                    chmanager->getCache(cacheNumber).addRecord(key,json::parse(_msg.msg));
                }
            }
            else
            {
                _msg.msg = jsc.dump();
                cout << "缓存命中" << endl;
                logInfo("缓存命中");
            }
            _msg.id = 100;
            _msg.length =  _msg.msg.size();
        }
        else if(_msg.id == 2)
        {

            //查询缓存
            json jsc = chmanager->getCache(cacheNumber).doQuery(_msg.msg);

            //网页搜索
            WebPageQuery wpq(new SplitToolCppjieba());
            string res = wpq.doQuery(_msg.msg);
            json tmp = json::parse(res);
            vector<string> str  = tmp.get<vector<string>>();
            if(str.size() == 0)
            {
                json js_msg = "404 not found!";
                logError("404 not found!");
                _msg.msg = js_msg.get<string>();
            }
            else
            {
                //加入缓存
                json value = str;
                chmanager->getCache(cacheNumber).addRecord(key,value);
                _msg.msg = value.dump();
            }
            _msg.id = 200;
            _msg.length = _msg.msg.size();
        }
        //把消息准备好:将消息长度、消息ID、消息内容封装到string中
        string reply;
        reply.append((char*)&_msg.length,4);
        reply.append((char*)&_msg.id,4);
        reply.append(_msg.msg.c_str(),_msg.length);
        _conn->sendInLoop(reply);
        bzero(&_msg,sizeof(_msg));
    }
private:
    Train _msg;//对端发送过来的消息
    TcpConnectionPtr _conn;
};


class EchoServer {
public:
    EchoServer(const string & ip, unsigned short port)
    : _threadpool(4, 20) 
    , _server(ip, port)
    {
        _server.setAllCallbacks(std::bind(&EchoServer::onConnection, this, std::placeholders::_1),
                                std::bind(&EchoServer::onMessage, this, std::placeholders::_1),
                                std::bind(&EchoServer::onClose, this, std::placeholders::_1));
    }

    void onConnection(const TcpConnectionPtr & conn)
    {
        cout << conn->toString() << " has connected!" << endl;
    }

    //该函数在哪里执行？ 在IO线程中执行
    void onMessage(const TcpConnectionPtr & conn)
    {
        //获取数据
        Train trn;
        trn.length = *(int*)conn->receive(4).c_str();
        trn.id = *(int*)conn->receive(4).c_str();
        trn.msg = conn->receive(trn.length);
        
        //根据协议区分服务
        //1 关键字推荐服务        客户端收100
        //2 发送推荐的关键字      客户端200[返回的网页信息]
        
        
        //将消息封装成一个任务，交给线程池来处理
        MyTask task(trn, conn);
        _threadpool.addTask(std::bind(&MyTask::process, task));
    }

    void onClose(const TcpConnectionPtr & conn)
    {
        cout << conn->toString() << " has closed!" << endl;
    }

    void start()
    {   
        Timerfd timer(std::bind(&EchoServer::process, this),50,50);
        Thread timerThread(std::bind(&Timerfd::start,&timer));
        timerThread.start();
        _threadpool.start();
        _server.start();
        timerThread.stop();
    }

    void process()
    {
        //此处使用update更新
        cout<<"Timered is running!"<<endl;
        //调用缓存同步更新得方法
        CacheManager* chmanager = CacheManager::getInstance();
        chmanager->updateCache();
    }
private:
    ThreadPool _threadpool;
    TcpServer _server;
};

void test2()
{
    EchoServer server("127.0.0.1", 8888);
    server.start();
}

int main()
{
    Mylogger *plog = Mylogger::getInstance();
    test2();
    return 0;
}


